package com.cloudkinto.service.user.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cloudkinto.common.BeanConvert;
import com.cloudkinto.common.RedisKeyConstants;
import com.cloudkinto.common.common.MD5Util;
import com.cloudkinto.common.common.VerificationCodeUtil;
import com.cloudkinto.common.constant.SysConstant;
import com.cloudkinto.common.exception.BizException;
import com.cloudkinto.common.utils.OrderCodeUtil;
import com.cloudkinto.common.utils.dict.StaticDict;
import com.cloudkinto.common.web.PageResult;
import com.cloudkinto.common.web.SingleResult;
import com.cloudkinto.dao.*;
import com.cloudkinto.entity.*;
import com.cloudkinto.service.company.CompanyService;
import com.cloudkinto.service.file.FileMoreService;
import com.cloudkinto.service.file.FileService;
import com.cloudkinto.service.role.RoleService;
import com.cloudkinto.service.system.LoginLogService;
import com.cloudkinto.service.user.UserService;
import com.cloudkinto.service.user.UserWhiteService;
import com.cloudkinto.service.warehouse.WarehouseService;
import com.cloudkinto.session.UserSession;
import com.cloudkinto.session.UserSessionException;
import com.cloudkinto.session.UserSessionManager;
import com.cloudkinto.vo.company.CompanyPageVo;
import com.cloudkinto.vo.file.FileRes;
import com.cloudkinto.vo.menu.RolePageVo;
import com.cloudkinto.vo.role.menu.MenuNewTreeRes;
import com.cloudkinto.vo.user.*;
import com.cloudkinto.vo.user.login.ChangeWhReq;
import com.cloudkinto.vo.warehouse.WarehouseRes;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * service实现类
 * </p>
 *
 * @author 张永远
 * @since 2020-05-27
 */
@Service
@Transactional(rollbackFor = Exception.class)//事务回滚
public class UserServiceImpl extends ServiceImpl<UserDao, UserDo> implements UserService {
    @Value("${gbc.login.verificationCode}")
    private boolean verificationCode;
    @Value("${gbc.scheduling}")
    private String type;
    @Autowired
    private UserDao dao;
    @Autowired
    private FileService fileService;
    @Autowired
    private CompanyDao companyDao;
    @Autowired
    private CompanyService companyService;
    @Autowired
    private FileDao fileDao;
    @Autowired
    private RoleDao roleDao;
    @Autowired
    private MenuDao menuDao;
    @Autowired
    private RoleService roleService;
    @Autowired
    private DicBusinessItemDao dicBusinessItemDao;
    @Autowired
    private UserSessionManager userSessionManager;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RoleMenuRelationDao roleMenuRelationDao;
    @Autowired
    private WarehouseService warehouseService;
    @Autowired
    private UserWhiteDao userWhiteDao;
    @Autowired
    private UserWhiteService userWhiteService;
    @Autowired
    private LoginLogService loginLogService;
    @Autowired
    private FileMoreService fileMoreService;

    @Override
    public UserLoginSuccessRes login(UserLoginReq req, HttpServletRequest request, String source) {
        //校验验证码
        if (verificationCode) {
            String verificationCode = (String) redisTemplate.opsForValue().get("verificationCode:" + req.getKey());
            if (StringUtils.isBlank(verificationCode)) {
                throw new BizException(SysConstant.Login_VerCode_Expired);
            } else if (!(verificationCode.equals(req.getVerificationCode()))) {
                throw new BizException(SysConstant.Login_VerCode_InCorrect);
            }
        }
        LambdaQueryWrapper<UserDo> wrapper = new LambdaQueryWrapper<>();
        if ("api".equals(source)) {
            wrapper.eq(UserDo::getUserAccount, req.getUserAccount())
                    .eq(UserDo::getUserType, StaticDict.System_RoleType.Labella_New_Back.getValue())
                    .eq(UserDo::getUserPassword, req.getUserPassword());
        } else {
            MD5Util md5 = new MD5Util(SysConstant.SALT_STRING, "MD5");
            Integer roleType = StaticDict.System_RoleType.getRoleType(source);
            if (roleType == null) throw new BizException(SysConstant.Login_Error_AccountPassword);
            wrapper.eq(UserDo::getUserAccount, req.getUserAccount())
                    .eq(UserDo::getUserType, roleType)
                    .eq(UserDo::getUserPassword, md5.encode(req.getUserPassword()));
        }
        UserDo userDo = this.baseMapper.selectOne(wrapper);
        if (userDo == null) {
            throw new BizException(SysConstant.Login_Error_AccountPassword);
        }
        if (userDo.getUserStatus() == 2) {
            throw new BizException(SysConstant.Login_Error_Account_Disable);
        }
        if (userDo.getUserStatus() == 0) {
            throw new BizException(SysConstant.Login_Error_Account_NotPass);
        }
        //新增登录日志
        this.addLoginLog(userDo, source, request);
        //创建会话
        UserSession session = userSessionManager.createSession(userDo, source);
        UserLoginSuccessRes res = this.getUserLoginSuccess(userDo, session, source);
        //登录成功 session域中改变登陆人
        request.getSession().setAttribute(UserSession.SESSION_ID_KEY, session);
        LambdaUpdateWrapper<UserDo> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(UserDo::getId, userDo.getId());
        updateWrapper.set(UserDo::getLastLoginTime, new Date());
        this.update(updateWrapper);
        return res;
    }

    private void addLoginLog(UserDo userDo, String source, HttpServletRequest request) {
        LoginLogDo loginLogDo = new LoginLogDo();
        loginLogDo.setTenantId(userDo.getTenantId());
        loginLogDo.setCompanyId(userDo.getCompanyId());
        loginLogDo.setLoginTime(DateUtil.date());
        loginLogDo.setLoginIp(ServletUtil.getClientIP(request));
        loginLogDo.setLoginUserId(userDo.getId());
        loginLogDo.setLoginUsername(userDo.getUserName());
        UserAgent ua = UserAgentUtil.parse(request.getHeader("user-agent"));
        if (ua != null)
            loginLogDo.setLoginDevice(ua.getOs() + "/" + ua.getBrowser() + " " + ua.getVersion());
        loginLogDo.setSource(source.toUpperCase());
        loginLogService.save(loginLogDo);
    }

    public UserLoginSuccessRes getUserLoginSuccess(UserDo userDo, UserSession session, String source) {
        UserLoginSuccessRes res = BeanConvert.INSTANCE.userLoginSuccessRes(session);
        RoleDo role = roleDao.selectById(userDo.getRoleId());
        if (role != null) {
            res.setRoleName(role.getRoleName());
            res.setDevCode(role.getDevCode());
        }
        res.setHeadUrl(fileService.getFilePath(userDo.getHeadFileId()));
        if (!"api".equals(source))
            res.setButton(roleService.getButton(userDo.getRoleId(), StaticDict.System_MenuType.getSystemMenuType(source)));
        return res;
    }

    //切换仓库
    @Override
    public UserLoginSuccessRes changeWh(HttpServletRequest request, ChangeWhReq req, Long userId, Long tenantId) {
        String token = request.getHeader("token");
        UserSession session = userSessionManager.getSession(token);
        if (session == null) throw new UserSessionException();
        UserDo userDo = dao.selectById(session.getUserId());
        if (userDo == null) throw new BizException(SysConstant.User_NotExist);

        List<WarehouseRes> warehouseResList = warehouseService.getList(StaticDict.System_Source.WMS.getValue(), userId, tenantId);
        List<Long> collect = warehouseResList.stream().map(WarehouseRes::getId).collect(Collectors.toList());
        if (req.getWhId() != null && !collect.contains(req.getWhId())) {
            throw new BizException(SysConstant.Storage_No_Power);
        }
        if (req.getWhId() != null) {
            session.setStorageId(req.getWhId());
        }
        UserLoginSuccessRes res = this.getUserLoginSuccess(userDo, session, "wms");
        if (req.getWhId() == null) return res;
        userSessionManager.saveSession(session);
        //登录成功 session域中改变登陆人
        request.getSession().setAttribute(UserSession.SESSION_ID_KEY, session);
        if (req.getWhId() != null) {
            //上次todo 缓存 仓库
            Map<String, String> whMap = redisTemplate.opsForHash().entries(RedisKeyConstants.WMS_LastLogin_WhId);
            whMap.put(userDo.getId() + "", req.getWhId() + "");
            redisTemplate.opsForHash().putAll(RedisKeyConstants.WMS_LastLogin_WhId, whMap);
        }
        return res;
    }


    @Override
    public List<MenuNewTreeRes> getMenuTree(String token, String source) {
        //根据token获取 用户信息
        if (StringUtils.isBlank(token)) {
            throw new BizException(SysConstant.User_Session_Not_Exist);
        }
        Object o = redisTemplate.opsForValue().get("USER_SESSION_TOKEN:" + token);
        if (o == null) {
            throw new BizException(SysConstant.User_Session_Not_Exist);
        }
        UserSession userSession = JSONObject.parseObject(o.toString(), UserSession.class);
        if (userSession == null) {
            throw new BizException(SysConstant.User_Session_Not_Exist);
        }
        UserDo userDo = dao.selectById(userSession.getUserId());
        if (userDo == null) {
            throw new BizException(SysConstant.User_NotExist);
        }
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        String i18n = "ch";
        if (servletRequestAttributes != null) {
            i18n = servletRequestAttributes.getRequest().getHeader("lang");
        }
        return roleService.getMenuTree(userDo.getRoleId(), StaticDict.System_MenuType.getSystemMenuType(source), userDo.getCompanyId());
    }


    /**
     * 获取用户信息
     *
     * @return
     */
    @Override
    public UserInfoRes getUserInfo(String token, String source) {
        //根据token获取 用户信息
        if (StringUtils.isBlank(token)) {
            throw new BizException(SysConstant.User_Session_Not_Exist);
        }
        Object o = redisTemplate.opsForValue().get("USER_SESSION_TOKEN:" + token);
        if (o == null) {
            throw new BizException(SysConstant.User_Session_Not_Exist);
        }
        UserSession userSession = JSONObject.parseObject(o.toString(), UserSession.class);
        if (userSession == null) {
            throw new BizException(SysConstant.User_Session_Not_Exist);
        }
        UserDo userDo = dao.selectById(userSession.getUserId());
        if (userDo == null) {
            throw new BizException(SysConstant.User_NotExist);
        }
        if (userDo.getUserStatus() == 2) {
            // 会话失效
            throw new UserSessionException(SysConstant.Login_Error_Account_Disable);
        }
        //判断 不能用前台的token 请求后台api
        if (!Objects.equals(StaticDict.System_RoleType.getRoleType(source), userDo.getUserType())) {
            throw new UserSessionException(SysConstant.NoPower);
        }
        UserInfoRes res = new UserInfoRes();
        BeanUtils.copyProperties(userDo, res);
        res.setSessionId(token);
        res.setUserId(userDo.getId());
        res.setTenantId(userDo.getTenantId());
        if (userSession.getStorageId() != null) {
            List<Long> collect = warehouseService.getList(source, userDo.getId(), userDo.getTenantId()).stream().map(WarehouseRes::getId).collect(Collectors.toList());
            if (collect.contains(userSession.getStorageId())) {
                res.setStorageId(userSession.getStorageId());
            }
            else {
                res.setStorageId(CollUtil.isEmpty(collect) ? -1 : collect.get(0));
            }
        }
        res.setHeadUrl(fileService.getFilePath(userDo.getHeadFileId()));
        res.setButton(roleService.getButton(userDo.getRoleId(), StaticDict.System_MenuType.getSystemMenuType(source)));
        //角色
        RoleDo roleDo = roleDao.selectById(userDo.getRoleId());
        if (roleDo != null) {
            res.setRoleName(roleDo.getRoleName());
            res.setDevCode(roleDo.getDevCode());
        }
        return res;
    }

    @Override
    public String getHeaderUrl(String type) {
        FileMoreDo picFileList = fileMoreService.getOne(new LambdaQueryWrapper<FileMoreDo>()
                .eq(FileMoreDo::getMailId, -1L)
                .eq(FileMoreDo::getType, type).last(" order by id desc limit 1"));
        if (picFileList == null) {
            return null;
        }
        return fileService.getFilePath(picFileList.getFileId());
    }

    @Override
    public UserLoginSuccessRes main(String token, String source) {
        UserSession session = userSessionManager.getSession(token);
        if (session == null) throw new UserSessionException();
        UserLoginSuccessRes res = new UserLoginSuccessRes();
        UserDo userDo = dao.selectById(session.getUserId());
        if (userDo == null) throw new BizException("用户不存");
        res.setUserId(session.getUserId());
        res.setSessionId(session.getSessionId());
        res.setUserAccount(userDo.getUserAccount());
        res.setUserName(userDo.getUserName());
        res.setHeadUrl(fileService.getFilePath(userDo.getHeadFileId()));
        res.setMenuTree(roleService.getMenuTree(userDo.getRoleId(), StaticDict.System_MenuType.getSystemMenuType(source), userDo.getCompanyId()));
        res.setButton(roleService.getButton(userDo.getRoleId(), StaticDict.System_MenuType.getSystemMenuType(source)));
        return res;
    }

    @Override
    public void logout(String token) {
        userSessionManager.clearSession(token);
    }

    @Override
    public UserRegisterReq register(UserRegisterReq req) {
        checkRegister(req.getUserAccount());

        if (req.getCompanyFileId() != null) {
            fileService.uploadFile(req.getCompanyFileId());
        }

        CompanyDo companyDo = new CompanyDo();
        companyDo.setName(req.getCompanyName());
        companyDo.setCreateTime(new Date());
        companyDo.setDeleteFlag(SysConstant.DELETE_FLAG_FALSE);
        companyDao.insert(companyDo);
        companyDo.setCompanyCode(OrderCodeUtil.generateCompanyCode(companyDo.getId()));
        companyDao.updateById(companyDo);

        MD5Util md5 = new MD5Util(SysConstant.SALT_STRING, "MD5");

        UserDo userDo = new UserDo();
        userDo.setUserPassword(md5.encode(req.getUserPassword()));
        userDo.setUserAccount(req.getUserAccount());
        userDo.setUserName(req.getUserName());
        userDo.setUserMail(req.getUserMail());
        userDo.setUserPhone(req.getUserPhone());
        userDo.setCompanyId(companyDo.getId());
        userDo.setUserStatus(0);
        userDo.setCreateTime(new Date());
        userDo.setDeleteFlag(SysConstant.DELETE_FLAG_FALSE);
        //生成权限
        userDo.setRoleId(4L);
        dao.insert(userDo);
        return req;
    }


    private void checkRegister(String userAccount) {
        LambdaQueryWrapper<UserDo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserDo::getUserAccount, userAccount);
        int count = this.baseMapper.selectCount(wrapper);
        if (count > 0) {
            throw new BizException(SysConstant.Login_Error_Existed);
        }
    }

    @Override
    public Object detail(Long id, Long companyId, Long tenantId, String source) {
        return this.updateInit(id, companyId, tenantId, source);
    }


    @Override
    public SingleResult addInit(Long companyId, Long tenantId, String source) {
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("roleList", roleService.getList(companyId, tenantId, source));
        return SingleResult.success(resultMap);
    }

    @Override
    public UserBuildReq add(UserBuildReq req, Long userId, Long companyId, Long tenantId, String source) {
        this.checkRegister(req.getUserAccount());
        MD5Util md5 = new MD5Util(SysConstant.SALT_STRING, "MD5");
        UserDo entityDo = new UserDo();
        BeanUtils.copyProperties(req, entityDo);
        entityDo.setUserPassword(md5.encode(req.getUserPassword()));
        if (entityDo.getUserStatus() == null) {
            entityDo.setUserStatus(1);
        }
        entityDo.setUserType(StaticDict.System_RoleType.getRoleType(source));
        if ("oms".equals(source)) {
            entityDo.setCompanyId(companyId);
        }
        entityDo.setTenantId(tenantId);
        //头像
        if (req.getHeadFileId() != null) {
            fileService.uploadFile(req.getHeadFileId());
        }
        dao.insert(entityDo);

        //可见客户列表
        this.insertWhiteCus(req.getCusList(), req.getWhiteCus(), entityDo.getId(), userId);
        //可见仓库列表
        this.insertWhiteWh(req.getWhList(), req.getWhiteWh(), entityDo.getId(), userId);
        return req;
    }


    @Override
    public void check(UserCheckReq req, Long userId, Long companyId, Long tenantId, String source) {
        UserDo userDo = dao.selectById(req.getId());
        if (userDo == null) {
            return;
        }
        boolean flag = this.updateCheck(userDo, companyId, tenantId, source);
        if (!flag) return;
        if (Objects.equals(userDo.getUserStatus(), req.getStatus())) return;
        userDo.setUserStatus(req.getStatus());
        dao.updateById(userDo);
    }


    @Override
    public SingleResult updateInit(Long id, Long companyId, Long tenantId, String source) {
        UserDo entityDo = dao.selectById(id);
        if (entityDo == null) {
            throw new BizException(SysConstant.User_NotExist);
        }
        boolean flag = this.updateCheck(entityDo, companyId, tenantId, source);
        if (!flag) throw new BizException(SysConstant.NoPower);
        RoleDo roleDo = roleDao.selectById(entityDo.getRoleId());

        UserDetailRes res = new UserDetailRes(entityDo.getId(), entityDo.getUserAccount(), entityDo.getUserName(),
                roleDo == null ? null : roleDo.getDevCode(), entityDo.getRoleId(), roleDo == null ? "--" : roleDo.getRoleName(),
                entityDo.getUserMail(), entityDo.getUserPhone(), entityDo.getWhiteCus(), entityDo.getWhiteWh());
        res.setUserStatus(entityDo.getUserStatus());
        FileDo fileDo = fileDao.selectById(entityDo.getHeadFileId());
        if (fileDo != null) {
            res.setHeadFileUrl(fileService.getFilePath(fileDo.getId()));
            res.setHeadFileId(fileDo.getId());
            res.setFileName(fileDo.getFileName());
        }
        if ("omp".equals(source) && res.getWhiteCus() == 1) {
            //用户可见列表
            Map<String, Object> param = new HashMap<>();
            param.put("userId", entityDo.getId());
            param.put("source", source);
            param.put("tenantId", tenantId);
            List<CompanyPageVo> list = companyService.getList(param);
            res.setCusList(list);
        }
        if ("omp".equals(source) && res.getWhiteWh() == 1) {
            //用户可见仓库列表
            List<WarehouseRes> list = warehouseService.getList(source, id, tenantId);
            res.setWhList(list);
        }
        return SingleResult.success(res);
    }

    public boolean updateCheck(UserDo entityDo, Long companyId, Long tenantId, String source) {
        if ("oms".equals(source)) {
            return Objects.equals(entityDo.getCompanyId(), companyId);
        } else if ("omp".equals(source)) {
            return Objects.equals(entityDo.getTenantId(), tenantId);
        } else {
            return false;
        }
    }

    @Override
    public UserUpdateReq update(UserUpdateReq req, Long userId, Long companyId, Long tenantId, String source) {
        UserDo entityDo = dao.selectById(req.getId());
        if (entityDo == null) return null;
        boolean flag = this.updateCheck(entityDo, companyId, tenantId, source);
        if (!flag) return null;
        if (req.getHeadFileId() != null && !Objects.equals(req.getHeadFileId(), entityDo.getHeadFileId())) {
            fileService.uploadFile(req.getHeadFileId());
            fileService.deleteFile(entityDo.getHeadFileId());
        }
        entityDo.setUserName(req.getUserName());
        entityDo.setUserPhone(req.getUserPhone());
        entityDo.setRoleId(req.getRoleId());
        entityDo.setUserMail(req.getUserMail());
        entityDo.setHeadFileId(req.getHeadFileId());
        entityDo.setWhiteCus(req.getWhiteCus());
        entityDo.setWhiteWh(req.getWhiteWh());
        dao.updateById(entityDo);

        this.insertWhiteCus(req.getCusList(), req.getWhiteCus(), entityDo.getId(), userId);
        this.insertWhiteWh(req.getWhList(), req.getWhiteWh(), entityDo.getId(), userId);
        return req;
    }

    public void insertWhiteCus(List<CompanyPageVo> cusList, int whiteCus, Long id, Long userId) {
        if (whiteCus == 1) {
            //客户列表部分可见
            userWhiteDao.updateDelete(id, "company", userId);
            List<UserWhiteDo> whiteDos = new ArrayList<>();
            for (CompanyPageVo thirdId : cusList) {
                UserWhiteDo whiteDo = new UserWhiteDo(thirdId.getId(), id, "company", userId);
                whiteDos.add(whiteDo);
            }
            if (!whiteDos.isEmpty()) userWhiteDao.insertBatchMy(whiteDos);
        }
    }

    public void insertWhiteWh(List<WarehouseRes> cusList, int whiteCus, Long id, Long userId) {
        if (whiteCus == 1) {
            //客户列表部分可见
            userWhiteDao.updateDelete(id, "storage", userId);
            List<UserWhiteDo> whiteDos = new ArrayList<>();
            for (WarehouseRes thirdId : cusList) {
                UserWhiteDo whiteDo = new UserWhiteDo(thirdId.getId(), id, "storage", userId);
                whiteDos.add(whiteDo);
            }
            if (!whiteDos.isEmpty()) userWhiteDao.insertBatchMy(whiteDos);
        }
    }


    @Override
    public UpdatePasswordReq updatePassword(UpdatePasswordReq req, Long userId, Long companyId, Long tenantId, String source) {
        if (!req.getNewPassword().equals(req.getNewPasswordAgain())) {
            throw new BizException(SysConstant.Login_Update_NotSame);
        }
        UserDo entityDo = dao.selectById(req.getId());
        boolean flag = this.updateCheck(entityDo, companyId, tenantId, source);
        if (!flag) return null;
        MD5Util md5 = new MD5Util(SysConstant.SALT_STRING, "MD5");
        if (!(md5.encode(req.getPassword()).equals(entityDo.getUserPassword()))) {
            throw new BizException(SysConstant.Login_Error_OldPass);
        }

        entityDo.setUserPassword(md5.encode(req.getNewPassword()));
        dao.updateById(entityDo);
        return null;
    }

    @Override
    public int delete(Long id, Long userId, Long companyId, Long tenantId, String source) {
        UserDo entityDo = dao.selectById(id);
        if (entityDo == null) return 0;
        boolean flag = this.updateCheck(entityDo, companyId, tenantId, source);
        if (!flag) return 0;
        //如果是管理员账号，判断是不是最后一个
        RoleDo roleDo = roleDao.selectById(entityDo.getRoleId());
        if (roleDo != null && "clientAdmin".equals(roleDo.getDevCode())) {
            int count = dao.selectCount(new LambdaQueryWrapper<UserDo>()
                    .eq(UserDo::getRoleId, roleDo.getId())
                    .eq(UserDo::getUserStatus, 1)
                    .eq("oms".equals(source), UserDo::getCompanyId, companyId)
                    .eq(UserDo::getTenantId, tenantId));
            if (count <= 1) {
                throw new BizException(SysConstant.NoPower);
            }
        }
        return dao.deleteById(id);
    }

    @Override
    public SingleResult verificationCode() {
        Map map = VerificationCodeUtil.generateCode();
        String key = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set("verificationCode:" + key, map.get("result"), 5 * 60, TimeUnit.SECONDS);
        map.remove("result");
        map.put("key", key);
        return SingleResult.success(map);
    }

    @Override
    public SingleResult pageInit(Long companyId, Long tenantId, String source) {
        Map<String, Object> map = new HashMap<>();

        List<RolePageVo> roleList = roleService.getList(companyId, tenantId, source);
        map.put("roleList", roleList);
        map.put("warehouseList", warehouseService.getList(tenantId));
        return SingleResult.success(map);
    }

    @Override
    public PageResult getListPage(Map<String, Object> map) {
        IPage<UserPageVo> page = pageInit(map);
        page = dao.list(page, map);
        if ("omp".equals(map.get("source"))) {
            List<Long> userIds = page.getRecords().stream().filter(i -> i.getWhiteCus() == 1).map(UserPageVo::getId).collect(Collectors.toList());
            List<UserWhiteDo> whiteDos = userWhiteService.getList(userIds, "company");//所有 用户得可见客户列表
            List<Long> companyIds = whiteDos.stream().map(UserWhiteDo::getThirdId).distinct().collect(Collectors.toList());
            if (!companyIds.isEmpty()) {
                Map<String, Object> param = new HashMap<>();
                param.put("ids", companyIds);
                param.put("source", "wms");
                param.put("tenantId", map.get("tenantId"));
                List<CompanyPageVo> list = companyService.getList(param);
                Map<Long, List<UserWhiteDo>> collect = whiteDos.stream().collect(Collectors.groupingBy(UserWhiteDo::getUserId));
                for (UserPageVo record : page.getRecords()) {
                    if (collect.get(record.getId()) == null) continue;
                    List<Long> whiteCusIds = collect.get(record.getId()).stream().map(UserWhiteDo::getThirdId).collect(Collectors.toList());
                    if (whiteCusIds.isEmpty()) continue;
                    List<CompanyPageVo> cusList = list.stream().filter(i -> whiteCusIds.contains(i.getId())).collect(Collectors.toList());
                    record.setCusList(cusList);
                }
            }
        }
        PageResult result = new PageResult(page.getRecords(), (int) page.getCurrent(), (int) page.getSize(), (int) page.getTotal(), (int) page.getPages());
        return result;
    }

    private IPage<UserPageVo> pageInit(Map<String, Object> map) {
        IPage<UserPageVo> page = new Page<>();
        page.setSize(map.get("pageSize") != null ? Long.parseLong(map.get("pageSize").toString()) : 10);
        page.setCurrent(map.get("current") != null ? Long.parseLong(map.get("current").toString()) : 1);
        return page;
    }

    @Override
    public Long getUserTenantId(Long userId) {
        if (userId == null) return -1L;
        Object o = redisTemplate.opsForValue().get(RedisKeyConstants.UserTenant + userId);
        if (o != null) {
            return Long.parseLong(o.toString());
        }
        UserDo userDo = dao.selectById(userId);
        if (userDo == null) return -1L;
        redisTemplate.opsForValue().set(RedisKeyConstants.UserTenant + userId, userDo.getTenantId(), 60 * 60, TimeUnit.SECONDS);
        return userDo.getTenantId();
    }

    @Override
    public String getUserAccount(Long userId) {
        UserDo userDo = dao.selectById(userId);
        if (userDo != null) return userDo.getUserAccount();
        return null;
    }

    @Override
    public List<UserDo> getPickList(Long tenantId) {
        RoleDo roleDo = roleService.getOne(Wrappers.<RoleDo>lambdaQuery()
                .eq(RoleDo::getTenantId, tenantId)
                .eq(RoleDo::getRoleType, 3)
                .and(i -> i.eq(RoleDo::getRoleName, "picker").or().eq(RoleDo::getRoleName, "拣货员"))
                .select(RoleDo::getId)
                .orderByDesc(RoleDo::getCreateTime)
                .last("limit 1")
        );
        if (Objects.isNull(roleDo)) {
            throw new BizException("未找到拣货员角色，请创建角色picker");
        }
        return this.list(Wrappers.<UserDo>lambdaQuery()
                .eq(UserDo::getTenantId, tenantId)
                .eq(UserDo::getRoleId, roleDo.getId())
                .eq(UserDo::getUserStatus, 1)
                .select(UserDo::getId, UserDo::getUserName)
        );
    }
}

